package agile.sudoku.core;

import java.util.Vector;


public class SudokuGrid {
	private Cell[][] cells;
	private int gridSeed;
	private int gridSize;
	private StartStateGenerator g;

	public SudokuGrid(int gridSeed) {
		this.gridSeed = gridSeed;
		gridSize = gridSeed * gridSeed;
		cells = new Cell[gridSize][gridSize];
		g = new StartStateGenerator();
		initialize();
	}

	private void initialize() {
		for (int i = 0; i < gridSize; i++) {
			for (int j = 0; j < gridSize; j++) {
				cells[i][j] = new Cell();
			}
		}
		Vector<StartStateElement> initializeElements = g.getElements();
		StartStateElement elem;
		for (int i = 0 ; i < initializeElements.size(); i++) {
			elem = initializeElements.get(i);
			cells[elem.getGridRow()][elem.getGridCol()].setValue(elem.getValue());
			cells[elem.getGridRow()][elem.getGridCol()].disable();
		}
		
	}

	public int numberOfCells() {
		return gridSize*gridSize;
	}

	

	public String toString() {
		String ret = "";
		for (int i = 0; i < gridSize; i++) {
			for (int j = 0; j < gridSize; j++) {
				ret = ret.concat(cells[i][j].toString());
			}
			ret = ret.concat("\n");
		}
		return ret;
	}

	public Cell getCell(int i, int j) {
		return cells[i][j];
	}

	public int getGridSize() {
		return gridSize;
	}

	public boolean setCell(int i, int j, int newValue) {
		if (i < 0 || i >= gridSize) {
			return false;
		}
		if (j < 0 || j >= gridSize) {
			return false;
		}
		if (newValue < 1 || newValue > gridSeed*gridSeed) {
			return false;
		}
		if (!cells[i][j].isEnabled()) {
			return false;
		} else {
			if (conflicts(i,j,newValue)) {
				return false;
			} else {
				cells[i][j].setValue(newValue);
				return true;
			}
		}
	}

	private boolean conflicts(int i, int j, int newValue) {
		for (int k = 0; k < gridSize; k++ ) {
			if (cells[i][k].getValue() == newValue) {
				return true;
			}
		}
		for (int k = 0; k < gridSize; k++ ) {
			if (cells[k][j].getValue() == newValue) {
				return true;
			}
		}
		if (conflictsTile(i,j,newValue)) {
			return true;
		}
		return false;
	}

	private boolean conflictsTile(int i, int j, int newValue) {
		for (int k = lowerBound(i); k < upperBound(i); k++) {
			for (int l = lowerBound(j); l < upperBound(j); l++) {
				if (cells[k][l].getValue() == newValue) {
					return true;
				}
			}
		}
		return false;
	}
	
	private int upperBound(int i) {
		return lowerBound(i)+gridSeed;
	}

	private int lowerBound(int i) {
		Double ret = Math.floor((float)i/(float)gridSeed);
		return gridSeed * ret.intValue();
	}

}
